package com.myplans.server.service;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.mahout.cf.taste.impl.model.jdbc.MySQLJDBCDataModel;
import org.apache.mahout.cf.taste.impl.recommender.CachingRecommender;
import org.apache.mahout.cf.taste.impl.recommender.slopeone.SlopeOneRecommender;
import org.apache.mahout.cf.taste.model.JDBCDataModel;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;

import com.google.gson.Gson;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.myplans.client.service.UserService;
import com.myplans.criteria.PlanSearchCriteria;
import com.myplans.criteria.UserSearchCriteria;
import com.myplans.server.util.ServiceLoader;
import com.myplans.server.util.Util;
import com.myplans.shared.FacebookUtil;
import com.myplans.shared.Plan;
import com.myplans.shared.User;
import com.myplans.vo.PlanValue;
import com.myplans.vo.UserValue;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

public class UserServiceImpl extends RemoteServiceServlet implements
		UserService {

	@Override
	public User signInUser(String email, String password) {
		UserSearchCriteria searchCriteria = new UserSearchCriteria();
		searchCriteria.setEmail(email);
		searchCriteria.setPassword(password);

		List<UserValue> userValues = ServiceLoader.getServiceInstance()
				.getUserService().getUsers(searchCriteria);

		if (userValues.size() > 0) {
			UserValue userValue = userValues.get(0);
			User user = new User();

			try {
				BeanUtils.copyProperties(user, userValue);
				return user;
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return null;
		} else {
			return null;
		}
	}

	@Override
	public User signUpUser(User user) {
		try {
			User signedInUser = signInUser(user.getEmail(), user.getPassword());

			if (signedInUser == null) {
				UserValue userValue = new UserValue();
				BeanUtils.copyProperties(userValue, user);
				if (userValue.getPassword() == null) {
					userValue.setPassword(userValue.getEmail());
				}
				if (userValue.getPicture() == null) {
					userValue.setPicture(Util.defaultImage);
				}
				userValue = ServiceLoader.getServiceInstance().getUserService()
						.createUser(userValue);
				BeanUtils.copyProperties(user, userValue);
				return user;
			} else {
				return signedInUser;
			}
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public User updateUser(User user) {
		try {
			UserValue userValue = new UserValue();
			BeanUtils.copyProperties(userValue, user);
			userValue = ServiceLoader.getServiceInstance().getUserService()
					.updateUser(userValue);
			BeanUtils.copyProperties(user, userValue);

			return user;
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public User createPlanForUser(Plan plan, User user) {
		try {
			UserValue userValue = new UserValue();
			BeanUtils.copyProperties(userValue, user);
			PlanValue planValue = new PlanValue();
			BeanUtils.copyProperties(planValue, plan);
			userValue = ServiceLoader.getServiceInstance().getUserService()
					.createPlanForUser(planValue, userValue);
			BeanUtils.copyProperties(user, userValue);

			return user;
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public User deletePlanForUser(Plan plan, User user) {
		try {
			UserValue userValue = new UserValue();
			BeanUtils.copyProperties(userValue, user);
			PlanValue planValue = new PlanValue();
			BeanUtils.copyProperties(planValue, plan);
			userValue = ServiceLoader.getServiceInstance().getUserService()
					.deletePlanForUser(planValue, userValue);
			BeanUtils.copyProperties(user, userValue);

			return user;
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public ArrayList<Plan> getPlansForUser(User user) {
		ArrayList<Plan> plans = new ArrayList<Plan>();
		try {
			if (user != null) {
				UserValue userValue = new UserValue();
				BeanUtils.copyProperties(userValue, user);
				List<PlanValue> planValues = ServiceLoader.getServiceInstance()
						.getUserService().getPlansForUser(userValue);
				for (PlanValue planValue : planValues) {
					Plan plan = new Plan();
					BeanUtils.copyProperties(plan, planValue);
					plans.add(plan);
				}
			}
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return plans;
	}

	@Override
	public ArrayList<Plan> getRecommendedPlansForUser(User user) {
		ArrayList<Plan> plans = new ArrayList<Plan>();
		try {
			if (user != null) {
				UserValue userValue = new UserValue();
				BeanUtils.copyProperties(userValue, user);

				// try {
				// MySQLJDBCIDMigrator model = new
				// MySQLJDBCIDMigrator(dataSource, "PLANS2USERS", "USERS_FK",
				// "PLANS_FK");
				// model.
				// File ratingsFile = new File("dummy.csv");
				// DataModel model = new FileDataModel(ratingsFile);
				// } catch (TasteException e) {
				// // TODO Auto-generated catch block
				// e.printStackTrace();
				// } catch (Exception e) {
				// e.printStackTrace();
				// }

				MysqlDataSource dataSource = new MysqlDataSource();
				dataSource.setServerName("localhost");
				dataSource.setPort(3306);
				dataSource.setUser("root");
				dataSource.setPassword("root");
				dataSource.setDatabaseName("myplans");
				JDBCDataModel model = new MySQLJDBCDataModel(dataSource,
						"PLANS2USERS", "USERS_FK", "PLANS_FK", "PREF", null);

				// create a simple recommender on our data
				CachingRecommender cachingRecommender = new CachingRecommender(new SlopeOneRecommender(model));

				List<RecommendedItem> recommendations = cachingRecommender.recommend(user.getId(), 5);

				for (RecommendedItem recommendedItem : recommendations) {
					PlanSearchCriteria planSearchCriteria = new PlanSearchCriteria();
					planSearchCriteria.setId(recommendedItem.getItemID());
					List<PlanValue> planValues = ServiceLoader.getServiceInstance().getPlanService()
							.getPlans(planSearchCriteria);
					if (planValues.size() > 0) {
						Plan plan = new Plan();
						BeanUtils.copyProperties(plan, planValues.get(0));
						
						List<User> users = new ArrayList<User>();
						for (UserValue userValue1 : planValues.get(0).getParticipants()) {
							User participant = new User();
							BeanUtils.copyProperties(participant, userValue1);
							users.add(participant);
						}
						plan.setAttendingUsers(users);
						
						plans.add(plan);
					}
				}
			}
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return plans;
	}

	@Override
	public ArrayList<User> getSubscriptionsForUser(User user) {
		ArrayList<User> subscriptions = new ArrayList<User>();
		try {
			if (user != null) {
				UserValue userValue = new UserValue();
				BeanUtils.copyProperties(userValue, user);
				List<UserValue> userValues = ServiceLoader.getServiceInstance()
						.getUserService().getSubscriptionsForUser(userValue);
				for (UserValue userVal : userValues) {
					user = new User();
					BeanUtils.copyProperties(user, userVal);
					subscriptions.add(user);
				}
			}
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return subscriptions;
	}

	@Override
	public User createSubscriptionForUser(User subscription, User user) {
		try {
			UserValue userValue = new UserValue();
			BeanUtils.copyProperties(userValue, user);
			UserValue subscriptionValue = new UserValue();
			BeanUtils.copyProperties(subscriptionValue, subscription);
			userValue = ServiceLoader.getServiceInstance().getUserService()
					.createSubscriptionForUser(subscriptionValue, userValue);
			BeanUtils.copyProperties(user, userValue);

			return user;
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public User deleteSubscriptionForUser(User subscription, User user) {
		try {
			UserValue userValue = new UserValue();
			BeanUtils.copyProperties(userValue, user);
			UserValue subscriptionValue = new UserValue();
			BeanUtils.copyProperties(subscriptionValue, subscription);
			userValue = ServiceLoader.getServiceInstance().getUserService()
					.deleteSubscriptionForUser(subscriptionValue, userValue);
			BeanUtils.copyProperties(user, userValue);

			return user;
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public User getFbUser(String authToken) {

		final String meUrl = FacebookUtil.getMeUrl(authToken);
		final String json = Util.fetchURL(meUrl);

		User fbUser = new Gson().fromJson(json, User.class);

		byte[] picture;
		try {
			picture = Util.getPictureFromUrl(FacebookUtil.getPictureUrl(fbUser
					.getId()));
			String s = "data:image/jpg" + ";base64,"
					+ new String(Base64.encodeBase64(picture));
			fbUser.setPicture(s);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// fbUser.setId(null);

		fbUser = signUpUser(fbUser);

		return fbUser;
	}

	@Override
	public String login(final String authToken) {
		final String url = FacebookUtil.getAuthorizeUrl();
		return Util.fetchURL(url);
	}

	private String encodeUrl(final String unencodedToken) {
		final String[] parts = unencodedToken.split("=");

		if (parts.length < 2) {
			return "";
		}

		return "access_token=" + Util.encode(parts[1]);
	}

}
